package cn.yfj.basic.service.impl;

import cn.yfj.basic.Constant.BaseConstant;
import cn.yfj.basic.config.BusinessException;
import cn.yfj.basic.domain.LoginDto;
import cn.yfj.basic.jwt.JwtUtils;
import cn.yfj.basic.jwt.LoginData;
import cn.yfj.basic.service.ILoginService;
import cn.yfj.basic.util.*;
import cn.yfj.org.domain.Employee;
import cn.yfj.org.domain.Shop;
import cn.yfj.org.mapper.EmployeeMapper;
import cn.yfj.org.mapper.ShopMapper;
import cn.yfj.system.domain.Menu;
import cn.yfj.user.domain.Logininfo;
import cn.yfj.user.domain.User;
import cn.yfj.user.domain.Wxuser;
import cn.yfj.user.mapper.LogininfoMapper;
import cn.yfj.user.mapper.UserMapper;
import cn.yfj.user.mapper.WxuserMapper;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.security.PrivateKey;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class LoginServiceImpl implements ILoginService {
    @Autowired
    LogininfoMapper logininfoMapper;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    private ShopMapper shopMapper;
    @Autowired
    private WxuserMapper wxuserMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private EmployeeMapper employeeMapper;
    /*获取私有密钥进行签名*/
    @Value("${jwt.rsa.pri}")//SEL
    private String priKey;

    @Override
    public Map<String, Object> account(LoginDto dto) {
        //参数校验
        if (StringUtils.isEmpty(dto.getUsername())
                || StringUtils.isEmpty(dto.getPassword())
                || StringUtils.isEmpty(dto.getType())
        ) {
            throw new BusinessException("参数有误");
        }
        //数据库进行查询并比较
        Logininfo logininfoTmp = logininfoMapper.loadByDto(dto);
        if (logininfoTmp == null) {
            throw new BusinessException("请填写正确账号");
        }
        //判断密码是否一致
        String salt = logininfoTmp.getSalt();
        String md5pwd = MD5Utils.encrypByMd5(dto.getPassword() + salt);
        if (!md5pwd.equals(logininfoTmp.getPassword())) {
            throw new BusinessException("账号或密码错误");
        }
        //查询账号是否被禁用
        if (logininfoTmp.getDisable() == 0) {
            throw new BusinessException("账号已被禁用");
        }
       /* //将登陆信息存到Redis,30分钟后过期
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(
                token,
                logininfoTmp,
                30,
                TimeUnit.MINUTES
        );
        Shop shop = shopMapper.loadById(48L);
        String logo = shop.getLogo();
        System.out.println(logo);
        //返回token加logininfo
        Map<String, Object> map = new HashMap<>();
        map.put("avatar", logo);
        map.put("token", token);
        logininfoTmp.setSalt(null);
        logininfoTmp.setPassword(null);
        map.put("logininfo", logininfoTmp);*/

        return loginSuccessJwtHandler(logininfoTmp);
    }

    private Map<String, Object> loginSuccessJwtHandler(Logininfo logininfoTmp) {
        LoginData loginData = new LoginData();
        try {
            //type等于1为用户
            if (logininfoTmp.getType()==1){
                User user = userMapper.loadUserByLogininfoId(logininfoTmp.getId());
                user.setSalt(null);//敏感字段置空
                user.setPassword(null);
                loginData.setUser(user);
            }else {//type为0是员工
                Employee employee = employeeMapper.loadEmpByLogininfoId(logininfoTmp.getId());
                employee.setSalt(null); //敏感字段置空
                employee.setPassword(null);
                loginData.setAdmin(employee);
                //查询当前登录人所拥有的权限
                List<String> snList = employeeMapper.loadPerssionSnByLogininfoId(logininfoTmp.getId());
                //查询当前登录人所拥有的菜单权限
                List<Menu> menus = employeeMapper.loadMenusByLogininfoId(logininfoTmp.getId());
                loginData.setPermissions(snList);
                loginData.setMenus(menus);
            }
            /*获取私有密钥进行签名*/
            PrivateKey privateKey = RsaUtils.getPrivateKey(JwtUtils.class.getClassLoader().getResource(priKey).getFile());
            //使用工具类进行加密
            String jwtStr = JwtUtils.generateTokenExpireInMinutes(loginData, privateKey, 600);
            //打印日志
            log.info("jwt:{}",jwtStr);
            Map<String, Object> map = new HashMap<>();
            map.put("token",jwtStr);
            if (loginData.getUser()!=null){
                map.put("user",loginData.getUser());
            }else {
                map.put("user",loginData.getAdmin());
            }
            map.put("menus",loginData.getMenus());
            map.put("permissions",loginData.getPermissions());
            return map;
        } catch (Exception e) {
            e.printStackTrace();
        }
    return null;
    }

    @Override
    public AjaxResult wechat(Map<String, String> map) {
        //校验code，不可能为空不用校验
        //根据code从微信去获取token+openId
        String code = map.get("code");
        /*微信取值访问链接设置*/
        String tokenUrl = BaseConstant.LoginConstant.TOKEN_URL
                .replace("SECRET", BaseConstant.LoginConstant.SECRET)
                .replace("CODE", code)
                .replace("APPID", BaseConstant.LoginConstant.APPID);
        /*访问*/
        String tokenStr = HttpClientUtils.httpGet(tokenUrl);
        /*取值*/
        JSONObject jsonObject = JSONObject.parseObject(tokenStr);
        /*获取token*/
        String accessToken = jsonObject.getString("access_token");
        /*获取openid*/
        String openId = jsonObject.getString("openid");
        /*查询数据库看是否是第一次登录*/
        Wxuser wxuser = wxuserMapper.loadByOpenId(openId);
        /*如果有即不是第一次扫码登录就直接登录*/
        if (wxuser != null && wxuser.getUserId() != null) {
            Logininfo logininfo = logininfoMapper.loadByUserId(wxuser.getUserId());
           // String token = UUID.randomUUID().toString();
         /*   redisTemplate.opsForValue().set(
                    token,
                    logininfo,   // 要把对象存储到redis 对象需要实现序列化接口
                    30,
                    TimeUnit.MINUTES
            );
            //6.返回token + logininfo
            Map<String, Object> mp = new HashMap<>();
            mp.put("token",token);
            //作为高级技师，应该考虑到将一些敏感字段置空  salt pwd
            logininfo.setSalt(null);
            logininfo.setPassword(null);
            mp.put("logininfo",logininfo);
            return AjaxResult.me().setSuccess(true).setResultobj(mp);*/
        return AjaxResult.me().setSuccess(true).setResultobj(loginSuccessJwtHandler(logininfo));

        }
        /*如果没有就调到绑定界面*/
        String binderParams = "?accessToken=" + accessToken + "&openId=" + openId;
        return AjaxResult.me().setSuccess(false).setResultobj(binderParams);

    }

    @Override
    public Map<String, Object> binder(Map<String, String> map) {
        /*获取前端传过来数据*/
        String phone = map.get("phone");
        String accessToken = map.get("accessToken");
        String openId = map.get("openId");
        String password = map.get("password");
        /*判断手机号是否被注册*/
        User user = userMapper.loadByPhone(phone);

        Logininfo logininfo = null;
        if (user != null) { //已经被注册
            logininfo = logininfoMapper.loadByUserId(user.getId());
            /*判断手机号是否绑定其他微信*/
            Wxuser wxu = wxuserMapper.loadByUserId(user.getId());
      if (wxu!=null) {
            throw new BusinessException("手机号已经绑定其他微信账号");
        }
        } else {
            //没注册
            user = initUser(phone, password);
            logininfo = user2Logininfo(user);
            logininfoMapper.save(logininfo);
            user.setLogininfoId(logininfo.getId());
            userMapper.save(user);
        }
        //根据token+openId查询微信用户信息
        String wxUserUrl = BaseConstant.LoginConstant.WXUSER_URL
                .replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId);
        String wxUserStr = HttpClientUtils.httpGet(wxUserUrl);
        //根据微信返回的信息创建t_wxuser，设置初始值
        Wxuser wxuser = JSONObject.parseObject(wxUserStr, Wxuser.class);
        //  t_wxuser绑定平台user_id
        // 保存数据
        wxuser.setUserId(user.getId());
        wxuserMapper.save(wxuser);
        //免密登录
/*
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(
                token,
                logininfo,   // 要把对象存储到redis 对象需要实现序列化接口
                30,
                TimeUnit.MINUTES
        );
        //返回token + logininfo
        Map<String, Object> mp = new HashMap<>();
        mp.put("token", token);
        //将一些敏感字段置空
        logininfo.setSalt(null);
        logininfo.setPassword(null);
        mp.put("logininfo", logininfo);
        return mp;*/
        return loginSuccessJwtHandler(logininfo);
    }


    private Logininfo user2Logininfo(User user) {
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user,logininfo);
        logininfo.setSalt(user.getSalt());
        //设置type
        logininfo.setType(1);
        return logininfo;
    }


    private User initUser(String phone, String password) {
        User user = new User();
        user.setPhone(phone);
        user.setUsername(phone);
        String salt = StrUtils.getComplexRandomString(32);
        String md5Pwd = MD5Utils.encrypByMd5(password + salt);
        user.setSalt(salt);
        user.setPassword(md5Pwd);
        return user;
    }
}
